package com.snack.common.utils;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

import org.apache.log4j.Logger;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class Image {
	private static final Logger LOGGER = Logger.getLogger(Image.class.getName());
	public static final float DEFAULT_JPEG_QUALITY = 0.85f;

	private BufferedImage image;

	public void release() {
		image = null;
	}

	public Image(BufferedImage image) {
		this.image = image;
	}

	public Image(byte[] bytes) {
		this.image = toBufferedImage(bytes);
	}

	public BufferedImage getBufferedImage() {
		return image;
	}

	public int getWidth() {
		if (image == null)
			return 0;
		return image.getWidth();
	}

	public int getHeight() {
		if (image == null)
			return 0;
		return image.getHeight();
	}

	public static byte[] read(File file) throws IOException {
		FileInputStream in = null;
		try {
			in = new FileInputStream(file);
			return read(in);
		} catch (IOException e) {
			throw e;
		} finally {
			if (in != null) {
				in.close();
			}
		}
	}

	public static byte[] read(URL url) throws IOException {
		InputStream in = null;
		try {
			in = url.openStream();
			return read(in);
		} catch (IOException e) {
			throw e;
		} finally {
			if (in != null) {
				in.close();
			}
		}
	}

	public static byte[] read(InputStream in) throws IOException {
		try {
			byte[] datas = IOUtils.toByteArray(in);
			return datas;
		} catch (IOException e) {
			throw e;
		}
	}

	public static String getFormatName(byte[] imgData) {
		ImageInputStream input = null;
		ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(imgData);
		try {
			input = ImageIO.createImageInputStream(byteArrayInputStream);
			Iterator<ImageReader> it = ImageIO.getImageReaders(input);
			if (it.hasNext()) {
				ImageReader reader = it.next();
				return reader.getFormatName();
			}
		} catch (Exception e) {
		} finally {
			try {
				if (input != null) {
					input.close();
				}
			} catch (Exception e) {
			}
			try {
				byteArrayInputStream.close();
			} catch (Exception e) {
			}
		}
		return null;
	}

	public static Image parse(File file) throws IOException {
		return new Image(read(file));
	}

	public static Image parse(URL url) throws IOException {
		InputStream in = null;
		try {
			in = url.openStream();
			return new Image(read(url.openStream()));
		} catch (IOException e) {
			throw e;
		} finally {
			if (in != null) {
				in.close();
				in = null;
			}
		}

	}

	public boolean cutTo(int tarWidth, int tarHeight) {
		if (image == null) {
			throw new RuntimeException("image file not be load.please execute 'load' function agin.");
		}

		int iSrcWidth = getWidth(); // 得到源图宽
		int iSrcHeight = getHeight(); // 得到源图长

		// 如果源图片的宽度和高度小于目标图片的宽度或高度，则直接返回原图
		if (iSrcWidth < tarWidth && iSrcHeight < tarHeight) {
			LOGGER.warn("source image size too small.");
			return true;
		}

		int iDstLeft = (iSrcWidth - tarWidth) / 2;
		int iDstTop = (iSrcHeight - tarHeight) / 2;

		// 剪裁---
		this.image = image.getSubimage(iDstLeft, iDstTop, tarWidth, tarHeight);

		return true;
	}

	public boolean zoomTo(int tarWidth, int tarHeight, boolean alpha) {

		// 创建BufferedImage对象
		int type = BufferedImage.TYPE_INT_ARGB;// 使得背景透明
		if (!alpha)
			type = BufferedImage.TYPE_INT_RGB;// 背景不透明
		BufferedImage tagImage = new BufferedImage(tarWidth, tarHeight, type);

		// 得到缩放后的原图
		java.awt.Image zoomImage = this.image.getScaledInstance(tarWidth, tarHeight, java.awt.Image.SCALE_SMOOTH);
		Graphics g = tagImage.getGraphics();

		// 如果为不透明，则绘制白色底
		if (!alpha) {
			Color c = g.getColor();
			g.setColor(Color.WHITE);
			g.fillRect(0, 0, tarWidth, tarHeight);
			g.setColor(c);
		}

		// 绘制图象到画布
		g.drawImage(zoomImage, 0, 0, null); // 绘制目标图
		g.dispose();

		this.image = tagImage;

		return true;
	}
	
	public byte[] getBytes(String format) {
		return toBytes(image, format);
	}

	public byte[] getJPEGBytes(float quality) {
		return toJPEGBytes(image, quality);
	}

	public void drawMarkImage(byte[] markBytes, int right, int bottom, boolean alpha) {
		BufferedImage markImage = toBufferedImage(markBytes);
		drawMarkImage(markImage, right, bottom, alpha);
	}

	/**
	 * 绘制水印图象
	 * 
	 * @param markImage
	 * @param right
	 * @param bottom
	 * @param alpha
	 */
	public void drawMarkImage(BufferedImage markImage, int right, int bottom, boolean alpha) {
		// 新图像
		int wideth = this.image.getWidth();
		int height = this.image.getHeight();

		// 创建BufferedImage对象
		int type = BufferedImage.TYPE_INT_ARGB;// 使得背景透明
		if (!alpha)
			type = BufferedImage.TYPE_INT_RGB;// 背景不透明
		BufferedImage tagImage = new BufferedImage(wideth, height, type);

		Graphics g = tagImage.createGraphics();

		// 如果为不透明，则绘制白色底
		if (!alpha) {
			Color c = g.getColor();
			g.setColor(Color.WHITE);
			g.fillRect(0, 0, wideth, height);
			g.setColor(c);
		}

		// 绘制原图
		g.drawImage(this.image, 0, 0, wideth, height, null);

		// 绘制水印文件
		int markWidth = markImage.getWidth();
		int markHeight = markImage.getHeight();
		g.drawImage(markImage, wideth - markWidth - right, height - markHeight - bottom, markWidth, markHeight, null);
		g.dispose();
		this.image = tagImage;
	}

	/**
	 * 将字节数组图象转换为BufferedImage对象
	 * 
	 * @param bytes
	 * @return
	 */
	public static BufferedImage toBufferedImage(byte[] bytes) {
		ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
		try {
			BufferedImage image = ImageIO.read(byteArrayInputStream);
			return image;
		} catch (IOException e) {
			throw new RuntimeException(e.getMessage());
		} finally {
			try {
				byteArrayInputStream.close();
			} catch (Exception e) {
			}
		}
	}
	
	/**
	 * 转换图象成指定格式的字节流
	 * @param image
	 * @param format
	 * @return
	 */
	public static byte[] toBytes(BufferedImage image , String format){
		if("JPEG".equals(format.toUpperCase()) || "JPG".equals(format.toUpperCase())){
			return toJPEGBytes(image,DEFAULT_JPEG_QUALITY);
		}
		
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		try {
			ImageIO.write(image, format, bos);
			return bos.toByteArray();
		} catch (IOException e) {
			throw new RuntimeException(e.getMessage());
		} finally {
			try {
				bos.close();
			} catch (IOException e) {

			}
		}
	}
	
	/**
	 * 转换图像为JPEG字节流
	 * @param image
	 * @param quality
	 * @return
	 */
	public static byte[] toJPEGBytes(BufferedImage image,float quality) {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		try {
			JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bos);
			JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(image);
			param.setQuality(quality, false);
			encoder.setJPEGEncodeParam(param);
			encoder.encode(image);
			return bos.toByteArray();
		} catch (IOException e) {
			throw new RuntimeException(e.getMessage());
		} finally {
			try {
				bos.close();
			} catch (IOException e) {

			}
		}
	}

	/**
	 * 将图片等比缩小到固定宽度,如果原图较小则不缩放.
	 * 
	 * @param data
	 * @param width
	 * @return
	 */
	public static byte[] fixWidth(byte[] data, int width, String format) {
		try {
			Image image = new Image(data);

			int imgW = image.getWidth();
			int imgH = image.getHeight();

			double wRate = ((double) imgW / (double) width);

			int height = (int) (imgH / wRate);

			boolean alpha = false;
			if ("PNG".equals(format.toUpperCase())) {
				alpha = true;
			}

			image.zoomTo(width, height, alpha);
			data = image.getBytes(format);

		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
		}
		return data;
	}

	/**
	 * 将图片缩放剪切到固定尺寸
	 * 
	 * @param data
	 * @param width
	 * @param height
	 * @return
	 */
	public static byte[] fixSize(byte[] data, int width, int height, String format) {
		try {

			Image image = new Image(data);

			int imgW = image.getWidth();
			int imgH = image.getHeight();

			if (imgW == width && imgH == height) {
				return data;
			}

			double wRate = ((double) imgW / (double) width);
			double hRate = ((double) imgH / (double) height);

			int zoomW = width;
			int zoomH = height;

			if (wRate < hRate) {
				zoomW = (int) ((double) imgW / wRate) + 1;
				zoomH = (int) ((double) imgH / wRate) + 1;
			} else {
				zoomW = (int) ((double) imgW / hRate) + 1;
				zoomH = (int) ((double) imgH / hRate) + 1;
			}

			boolean alpha = false;
			if ("PNG".equals(format.toUpperCase())) {
				alpha = true;
			}

			image.zoomTo(zoomW, zoomH, alpha);
			image.cutTo(width, height);
			data = image.getBytes(format);

		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
		}
		return data;
	}

}
